module mul(
        input           i_clk,
        input           i_rst,
        input   [31:0]  i_a,
        input   [31:0]  i_b,
        input           i_sign,
        input           i_add,
        input   [63:0]  i_addend,
        input           i_valid,
        output  [31:0]  o_hi,
        output  [31:0]  o_lo,
        output          o_ready
);

reg [31:0] a;
reg [31:0] b;
reg        add;
reg [63:0] addend;
reg [31:0] hi;
reg [31:0] lo;
reg [ 5:0] cnt;
reg        sign;
reg        prod_ready;
reg        ready;

wire udone = cnt[5];

assign o_ready = ready;

wire [32:0] adder_out;

wire [31:0] x = &cnt[4:0] ? {1'b0, {31{sign}}} : {sign, 31'b0} ;

halfadder #(32) u_halfadder(
        .a   (hi),
        .b   (udone ? 32'h80000001 : a&{32{b[0]}}^x),
        .s   (adder_out[31:0]),
        .cout(adder_out[32  ])
);

assign o_hi = hi;
assign o_lo = lo;

always @(posedge i_clk) begin
        if (i_rst) begin
                sign <= 1'b0;
                ready <= 1'b1;
        end else begin
                if (ready) begin
                        if (i_valid) begin
                                a <= i_a;
                                b <= i_b;
                                add <= i_add;
                                addend <= i_addend;
                                hi <= 0;
                                lo <= 0;
                                cnt <= 6'b0;
                                sign <= i_sign;
                                prod_ready <= 1'b0;
                                ready <= 1'b0;
                        end
                end else begin
                        if (prod_ready) begin
                                {hi, lo} <= {hi, lo} + addend;
                                ready <= 1'b1;
                        end else begin
                                if (udone) begin
                                        hi <= adder_out[31:0];
                                        prod_ready <= 1'b1;
                                        ready <= ~add;
                                end else begin
                                        b <= {1'b0, b[31:1]};
                                        hi <= adder_out[32:1];
                                        lo <= {adder_out[0], lo[31:1]};
                                        cnt <= cnt+6'b1;
                                        prod_ready <= &cnt[4:0] & ~sign;
                                        ready <= &cnt[4:0] & ~sign & ~add;
                                end
                        end
                end
        end
end

endmodule
